{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 简介\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>YiJingFramework.Nongli, 4.1.0</span></li></ul></div></div>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#r \"nuget:YiJingFramework.Nongli\"\n",
    "using YiJingFramework.Nongli.Extensions;\n",
    "using YiJingFramework.Nongli.Lunar;\n",
    "using YiJingFramework.Nongli.Solar;\n",
    "using YiJingFramework.PrimitiveTypes;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "此包提供了对中国农历的支持。\n",
    "\n",
    "此包是通过打表的方式获取的节气等信息，而非直接从天文原理出发进行的计算。因此，这里首先要感谢 [lunar-csharp](https://www.nuget.org/packages/lunar-csharp) 对相关社区作出的巨大贡献。本包所有用到的节气表等都是通过该包进行生成的，本包的测试项目也是依赖于该包的。\n",
    "\n",
    "相比而言， lunar-csharp 非常强调“无依赖”，其功能非常丰富，但都汇集在同一个包中，且与日期本身关联性很强。以其提供的冲煞功能为例，可以获取某日时的日冲、时冲等，但不方便直接获取某个地支的六冲。而本包作为 YiJingFramework 中的一部分，与其他包共用 `Tiangan` 、 `Dizhi` 等类型。于是此包可以专注于农历日期本身，而更多的功能将由其他的包另外提供。\n",
    "\n",
    "同时， lunar-csharp 支持的时间跨度非常大。除了向后的推演计算，更困难的是还支持向前的查询，因为古时的历法系统其实是相对混乱的，会出现各种例外情况。这些都需要进行相关的研究才能确定如何取舍，不能完全根据现在的天文情况进行推断。本包考虑到在非专业情况下，一般不会需要古时的日期，更不会把它在农历和公历之间进行转换，而且由于是通过打表进行实现的，因此，本包没有支持太长的时间跨度。在有需要的情况下，更新一下相关表格就即可进行扩展。\n",
    "\n",
    "本包使用起来也比较简单，举例而言，要获取今日的农历日期："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "癸卯年 平7月 11日 戌时\n",
      "二〇二三年七月十一\n",
      "癸卯 庚申 丙辰 戊戌\n"
     ]
    }
   ],
   "source": [
    "DateTime now = new DateTime(2023, 8, 26, 20, 44, 11);\n",
    "LunarDateTime lunar = LunarDateTime.FromGregorian(now);\n",
    "\n",
    "var n = $\"{lunar.Nian:C}年\";\n",
    "var y = $\"{(lunar.IsRunyue ? '闰' : '平')}{lunar.Yue}月\";\n",
    "var r = $\"{lunar.Ri}日\";\n",
    "var s = $\"{lunar.Shi:C}时\";\n",
    "Console.WriteLine($\"{n} {y} {r} {s}\");\n",
    "s = $\"{lunar.YearInChinese()}年{lunar.YueInChinese()}月{lunar.RiInChinese()}\";\n",
    "Console.WriteLine(s);\n",
    "\n",
    "SolarDateTime solar = SolarDateTime.FromGregorian(now);\n",
    "s = $\"{solar.Nian:C} {solar.Yue:C} {solar.Ri:C} {solar.Shi:C}\";\n",
    "Console.WriteLine(s);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "此包区分了农历的阳历部分和阴历部分。其中，阳历部分即干支历，年月日时均以干支表示；阴历部分即几月初几之类，月与日用数字表示，但时辰和年仍使用干支。\n",
    "\n",
    "上述代码其实是演示了如何从公历转为农历。同时，此包也提供了从农历转到公历的方式：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "N:Guimao2023 Y:C01 R:15 S:Chen\n",
      "2/5/2023 8:00:00 AM\n"
     ]
    }
   ],
   "source": [
    "LunarNian nian = LunarNian.FromGregorian(2023);\n",
    "LunarYue yue = nian.Yues[0];\n",
    "LunarDateTime lunar = yue.GetDateTime(ri: 15, shi: Dizhi.Chen);\n",
    "Console.WriteLine(lunar);\n",
    "Console.WriteLine(lunar.ToGregorian());"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "其中我们使用了 `LunarNian.FromGregorian(2023)` 以创建一个 `LunarNian` 。这里传入的 `2023` 以表示要获取的农历年年首位于公历 2023 年内，因为只靠干支是无法判断具体是哪一年的，于是就没法知道此年内月份的情况，更没有办法进行公历日期的转换。也就是说，其实农历年年首所在的公历年是会被切实记录的，可以通过 `LunarNian.Year` 和 `LunarDateTime.Year` 获取。阳历部分中也有类似的情况。\n",
    "\n",
    "同时，转换的结果是 `2023/2/5 8:00:00` ，这意味着它是使用时辰中间的时间作为小时数。同时，子时将会被认定为第二天，包括在 `LunarDateTime.FromGregorian` 中也是一样：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "N:Guimao2023 Y:C07 R:12 S:Zi\n",
      "8/27/2023 12:00:00 AM\n"
     ]
    }
   ],
   "source": [
    "var dateTime = DateTime.Parse(\"2023/8/26 23:12:22\");\n",
    "var lunar = LunarDateTime.FromGregorian(dateTime);\n",
    "Console.WriteLine(lunar);\n",
    "Console.WriteLine(lunar.ToGregorian());"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "在阳历部分中也有相同的情况，同时，阳历部分还涉及到交节换月。与大多数情况不同，为了和阴历部分保持一致，我们选择在交节当天换月，而不是交节时刻。如有需要，可以通过 `SolarYue.Jieling` 自行判断是否还没有到交节时刻：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Gengshen\n",
      "Jiwei\n",
      "Gengshen\n",
      "True\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "var dateTime8822 = DateTime.Parse(\"2023/8/8 22:59:59\");\n",
    "var solar8822 = SolarDateTime.FromGregorian(dateTime8822);\n",
    "Console.WriteLine(solar8822.Yue);\n",
    "\n",
    "var dateTime8722 = DateTime.Parse(\"2023/8/7 22:59:59\");\n",
    "var solar8722 = SolarDateTime.FromGregorian(dateTime8722);\n",
    "Console.WriteLine(solar8722.Yue);\n",
    "\n",
    "var dateTime8723 = DateTime.Parse(\"2023/8/7 23:00:00\");\n",
    "var solar8723 = SolarDateTime.FromGregorian(dateTime8723);\n",
    "Console.WriteLine(solar8723.Yue);\n",
    "\n",
    "var jieling = solar8723.SolarYue.Jieling;\n",
    "Console.WriteLine(dateTime8723 < jieling);\n",
    "Console.WriteLine(dateTime8822 > jieling);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "最后，关于节气，此包中，暂时还没有提供直接明确的支持，但也可以通过 `SolarYue` 间接获取：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "白露\n",
      "秋分\n"
     ]
    }
   ],
   "source": [
    "static string GetJieqi(DateTime dateTime)\n",
    "{\n",
    "    var jieqiTable = new string[] {\n",
    "        \"立春\", \"雨水\", \"惊蛰\", \"春分\", \"清明\", \"谷雨\",\n",
    "        \"立夏\", \"小满\", \"芒种\", \"夏至\", \"小暑\", \"大暑\",\n",
    "        \"立秋\", \"处暑\", \"白露\", \"秋分\", \"寒露\", \"霜降\",\n",
    "        \"立冬\", \"小雪\", \"大雪\", \"冬至\", \"小寒\", \"大寒\"\n",
    "    };\n",
    "    var solar = SolarDateTime.FromGregorian(dateTime);\n",
    "    var jieqiIndex = solar.SolarYue.IndexInNian * 2;\n",
    "    if (!solar.IsBeforeYueZhongqi)\n",
    "        jieqiIndex++;\n",
    "    return jieqiTable[jieqiIndex];\n",
    "}\n",
    "\n",
    "Console.WriteLine(GetJieqi(new DateTime(2023, 9, 22)));\n",
    "Console.WriteLine(GetJieqi(new DateTime(2023, 9, 23)));"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "file_extension": ".cs",
   "mimetype": "text/x-csharp",
   "name": "python",
   "pygments_lexer": "csharp",
   "version": "3.12.2"
  },
  "polyglot_notebook": {
   "kernelInfo": {
    "defaultKernelName": "csharp",
    "items": [
     {
      "aliases": [],
      "name": "csharp"
     }
    ]
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
